const net = require("net"); // node 的tcp模块
// 对象词法分析
const HttpParser = require("./http-parser");
// 解析html
const HtmlParser = require("htmlparser2");
// 解析css
const css = require("css");
class HTTPRequest {
  constructor(options = {}) {
    this.host = options.host;
    this.method = options.method || "GET";
    this.path = options.path || "/";
    this.port = options.port || 80;
    this.headers = options.headers;
  }
  send() {
    return new Promise((resolve, reject) => {
      // 构建http请求
      const rows = [];
      rows.push(`${this.method} ${this.path} HTTP/1.1`);
      Object.keys(this.headers).forEach((key) => {
        rows.push(`${key}: ${this.headers[key]}`);
      });
      let data = rows.join("\r\n") + "\r\n\r\n";
      // 创建tcp链接，传输http数据
      let socket = net.createConnection(
        {
          host: this.host,
          port: this.port,
        },
        () => {
          socket.write(data);
        }
      );
      const parser = new HttpParser();
      socket.on("data", (chunk) => {
        // console.log(chunk.toString());
        parser.parse(chunk);
        if (parser.result) {
          resolve(parser.result);
        }
      });
    });
  }
}
async function request() {
  const response = new HTTPRequest({
    host: "127.0.0.1",
    method: "GET",
    port: 3000,
    path: "/",
    headers: {
      name: "mock-request",
      num: 123,
    },
  });
  let { responseLine, headers, body } = await response.send();
  //   console.log(body);
  // 浏览器根据响应类型来解析文件 Context-Type: 'text/html'
  //  html => html-parser => dom tree
  let DOMTree = [{ type: "document", children: [] }];
  //   1:使用HtmlParser词法分析 分析html,解析出html
  const parser = new HtmlParser.Parser({
    onopentag(name, attributes) {
      //   console.log("start", name, attributes);
      let parent = DOMTree[DOMTree.length - 1];
      let element = {
        tagName: name,
        attributes: attributes,
        children: [],
        parent: parent,
      };
      parent.children.push(element);
      DOMTree.push(element);
    },
    ontext(text) {
      //   console.log(text);
      let parent = DOMTree[DOMTree.length - 1];
      let textNode = {
        type: "text",
        text,
      };
      parent.children.push(textNode);
    },
    onclosetag(name) {
      let parent = DOMTree[DOMTree.length - 1];
      //   console.log(name);
      if (name === "style") {
        parserCss(parent.children[0].text);
      }
      DOMTree.pop();
    },
  });
  parser.end(body);
  // 2:解析出DOMTree
  console.dir(DOMTree, { depth: null });
}
// 3:解析出stylesheet
function parserCss(style) {
  const ast = css.parse(style);
  console.log(ast.stylesheet.rules[0]);
  return ast.stylesheet;
}
/* node 模拟未实现 */
let cssRules = [];
function addCSSRules(text) {
  var _a;
  let ast = css.parse(text);
  console.log(JSON.stringify(ast, null, "    "));
  cssRules.push(
    ...((_a = ast.stylesheet) === null || _a === void 0 ? void 0 : _a.rules)
  );
}
// 浏览器上实现计算样式的方法
function computedCss(element) {
  let attrs = element.attributes; //
  element.computedStyle = {};
  Object.entries(attrs).forEach(([key, value]) => {
    cssRules.forEach((rule) => {
      let selector = rule.selectors[0];
      if (
        (selector == "#" + value && key == "id") ||
        (selector == "." + value && key == "class")
      ) {
        rule.declarations.forEach(({ property, value }) => {
          element.computedStyle[property] = value;
        });
      }
    });
  });
}
// 浏览器上计算布局绘制的方法
function layout(element) {
  //
  if ((Object.keys(element.computedStyle).length |= 0)) {
    let { background, width, height, top, left } = element.computedStyle;
    let code = `
     let canvas = document.createElement('canvas');
     canvas.width = window.innerWidth;
     canvas.height = window.innerHeight;
     let context = canvas.getContext('2d');
     context.fillStyle = "${background}";
     context.fillRect(${top}, ${left}, ${parseInt(width)}, ${parseInt(height)})
    `;
    fs.writeFileSync("./code.js", code);
  }
}
// 接下来浏览器会把DOMTree 和 stylesheet结合生成layout tree
request();
